package org.dizena.common.trace.httpclient;

import jakarta.annotation.Resource;
import org.dizena.common.trace.httpclient.handler.HttpClientMessageConverter;
import org.dizena.common.trace.httpclient.handler.HttpClientResponseErrorHandler;
import org.dizena.common.trace.httpclient.handler.HttpClientSSLRequestFactory;
import org.dizena.common.trace.httpclient.handler.HttpClientRequestTraceInterceptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.BufferingClientHttpRequestFactory;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.web.client.RestTemplate;

import java.util.List;

@Configuration
@EnableConfigurationProperties(HttpClientTraceAutoProperties.class)
@ConditionalOnProperty(
        prefix = "common.trace.client",
        value = {"enabled"},
        havingValue = "true"
)
public class HttpClientTraceAutoConfig implements CommandLineRunner {

    private Logger logger = LoggerFactory.getLogger(HttpClientTraceAutoConfig.class);

    @Resource
    private HttpClientTraceAutoProperties properties;

    private ApplicationEventPublisher publisher;

    @Autowired
    public void setPublisher(ApplicationEventPublisher publisher) {
        this.publisher = publisher;
    }

    @Bean
    public ClientHttpRequestFactory clientHttpRequestFactory() {
        HttpClientSSLRequestFactory factory = new HttpClientSSLRequestFactory();
        factory.setOutputStreaming(false);
        factory.setReadTimeout(properties.getReadTimeOut());
        factory.setConnectTimeout(properties.getConnectTimeOut());
        return factory;
    }

    @Bean
    @LoadBalanced
    @ConditionalOnMissingBean(value = RestTemplate.class)
    public RestTemplate restTemplate(@Autowired ClientHttpRequestFactory factory) {
        RestTemplate restTemplate = new RestTemplate();

        restTemplate.setRequestFactory(new BufferingClientHttpRequestFactory(factory));
        restTemplate.getMessageConverters().add(new HttpClientMessageConverter());
        restTemplate.setErrorHandler(new HttpClientResponseErrorHandler(publisher));

        List<ClientHttpRequestInterceptor> interceptors = restTemplate.getInterceptors();
        interceptors.add(new HttpClientRequestTraceInterceptor(properties, factory, publisher));
        restTemplate.setInterceptors(interceptors);

        return restTemplate;
    }

    @Bean
    public SmartInitializingSingleton smartInitializingSingleton(
            @Autowired List<RestTemplate> restTemplateList,
            @Autowired ClientHttpRequestFactory factory) {
        return () -> {
            for (RestTemplate restTemplate : restTemplateList) {
                List<ClientHttpRequestInterceptor> interceptors = restTemplate.getInterceptors();
                boolean isAdd = true;
                for (ClientHttpRequestInterceptor interceptor : interceptors) {
                    if (interceptor.getClass().equals(HttpClientRequestTraceInterceptor.class)) {
                        isAdd = false;
                        break;
                    }
                }
                if (isAdd) {
                    interceptors.add(new HttpClientRequestTraceInterceptor(properties, factory, publisher));
                }
                restTemplate.setInterceptors(interceptors);
            }
        };
    }

    @Override
    public void run(String... args) {
        logger.info("【自动化配置】---RestTemplate Trace 配置初始化");
    }
}
